#include <iostream>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>

#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
#include "renderer/VertexArray.h"
#include "glm/glm.hpp"
#include "Shader.h"
#include "Texture2D.h"
#include "renderer/Renderer.h"
#include "renderer/FrameBuffer.h"

GLFWwindow* m_Window = nullptr;

void SetDarkThemeColors() {
    auto& colors = ImGui::GetStyle().Colors;
    // Headers
    colors[ImGuiCol_Header] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f };
    colors[ImGuiCol_HeaderHovered] = ImVec4{ 0.3f, 0.305f, 0.31f, 1.0f };
    colors[ImGuiCol_HeaderActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };

    // Buttons
    colors[ImGuiCol_Button] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f };
    colors[ImGuiCol_ButtonHovered] = ImVec4{ 0.3f, 0.305f, 0.31f, 1.0f };
    colors[ImGuiCol_ButtonActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };

    // Frame BG
    colors[ImGuiCol_FrameBg] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f };
    colors[ImGuiCol_FrameBgHovered] = ImVec4{ 0.3f, 0.305f, 0.31f, 1.0f };
    colors[ImGuiCol_FrameBgActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };

    // Tabs
    colors[ImGuiCol_Tab] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };
    colors[ImGuiCol_TabHovered] = ImVec4{ 0.38f, 0.3805f, 0.381f, 1.0f };
    colors[ImGuiCol_TabActive] = ImVec4{ 0.28f, 0.2805f, 0.281f, 1.0f };
    colors[ImGuiCol_TabUnfocused] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };
    colors[ImGuiCol_TabUnfocusedActive] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f };

    // Title
    colors[ImGuiCol_TitleBg] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };
    colors[ImGuiCol_TitleBgActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };
    colors[ImGuiCol_TitleBgCollapsed] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f };

}

void GLFWErrorCallback(int errorCode, const char* message) {
    fprintf(stderr, "Error: %s\n", message);
}

void GLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GLFW_TRUE);
}

void ImGuiRenderer() {
    ImGui::Begin("Test");
    if (ImGui::Button("Click Me")) {
        printf("Click Me!");
    }
    ImGui::End();
}


int main() {
    glfwSetErrorCallback(GLFWErrorCallback);
    if (!glfwInit()) {
        return -1;
    }
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    int WinWidth = mode->width * 0.5;
    int WinHeight = mode->height * 0.5;

    m_Window = glfwCreateWindow(WinWidth, WinHeight, "Template", nullptr, nullptr);
    if (!m_Window) {
        glfwTerminate();
        return -1;
    }

    glfwSetKeyCallback(m_Window, GLFWKeyCallback);

    glfwMakeContextCurrent(m_Window);
    glfwSetWindowPos(m_Window, (mode->width - WinWidth) * 0.5, (mode->height - WinHeight) * 0.5);
    gladLoadGL(glfwGetProcAddress);
    glfwSwapInterval(1);

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();(void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
    // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
    io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
    io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;

    io.FontDefault = io.Fonts->AddFontFromFileTTF("resources/fonts/AlibabaPuHuiTi-3-55-Regular.ttf", 24.0f, nullptr, io.Fonts->GetGlyphRangesChineseFull());

    ImGui::StyleColorsDark();

    ImGuiStyle& style = ImGui::GetStyle();
    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
        style.WindowMinSize.x = 200.0f;
        style.WindowRounding = .0f;
        style.Colors[ImGuiCol_WindowBg].w = 1.0f;
    }

    SetDarkThemeColors();

    ImGui_ImplGlfw_InitForOpenGL(m_Window, true);
    ImGui_ImplOpenGL3_Init("#version 450");

    lazy::Renderer::Init();

    lazy::FramebufferSpecification spec;
    spec.Attachments = { lazy::FrameBufferTextureFormat::RGBA8, lazy::FrameBufferTextureFormat::RED_INTEGER, lazy::FrameBufferTextureFormat::Depth };
    spec.Width = WinWidth;
    spec.Height = WinHeight;
    lazy::Ref<lazy::FrameBuffer> m_frameBuffer = lazy::FrameBuffer::Create(spec);

    auto texture2D = lazy::Texture2D::LoadFromFile("resources/images/wall.jpg");

    while (!glfwWindowShouldClose(m_Window)) {
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();
        ImGui::ShowDemoWindow();


        ImGui::Begin("Viewport");
        ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail();
        glm::vec2 m_viewportSize = {viewportPanelSize.x, viewportPanelSize.y };
        if (m_viewportSize.x > 0.0f && m_viewportSize.y > 0.0f && // zero sized framebuffer is invalid
            (spec.Width != m_viewportSize.x || spec.Height != m_viewportSize.y)) {
            m_frameBuffer->Resize((uint32_t)m_viewportSize.x, (uint32_t)m_viewportSize.y);
        }
        uint32_t textureID = m_frameBuffer->GetColorAttachmentBufferID(0);
        ImGui::Image((void*)(uint64_t)textureID, ImVec2{m_viewportSize.x, m_viewportSize.y}, ImVec2{0, 1}, ImVec2{1, 0});
        ImGui::End();

        m_frameBuffer->Bind();
        lazy::Renderer::BeginScene(m_viewportSize.x / m_viewportSize.y);
        lazy::Renderer::DrawQuad({.0f, .0f, .0f}, {0.5f, 0.5f}, {1.0f, .0f, .0f, 1.0f}, texture2D);
        lazy::Renderer::EndScene();
        m_frameBuffer->ClearAttachment(1, -1);
        m_frameBuffer->Unbind();

        ImGuiRenderer();

        ImGui::Render();
        int width, height;
        glfwGetFramebufferSize(m_Window, &width, &height);
        const float ratio = width / (float) height;
        glViewport(0, 0, width, height);
        glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
            GLFWwindow * backup_current_content = glfwGetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            glfwMakeContextCurrent(backup_current_content);
        }

        glfwSwapBuffers(m_Window);
        glfwPollEvents();
    }

    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(m_Window);
    glfwTerminate();

    return 0;
}
